﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace KFGame
{
    public class DataFiter
    {

        /// <summary>
        /// 读格式类型
        /// (1)0x01 任意值行，符合数据格式的所有数据, （电位器，方向盘，持续收到数据）
        /// (2)0x02 对比相同字符段 开始位置 直到再次启动时才会发出第二次信号（按钮 一次信号）
        /// (3)0x04 非0x00 值字符段 ，开始位置 和段长度 （按下时持续接收信信号）只要不是0就会一直发出信息
        /// (4)0x08 开关型 点击，对比同字符段持续一段时间，只有发生变动时的信号。 开始时发出信息号直到关闭时会发出一次信号，（如：投币， 按钮按下 ）
        /// (5)0x10 轮值型，只发生变动时的信号，开始位置，和段长度 （变换灯） 当内容与前一次数据不同时就会发出通知
        /// (6)0x20 持续型，包函值内容， 当有值时会一直有通知，无包函时通知就停止
        /// </summary>
        [Flags]
        public enum FormatType
        {
            Default = 0x01,
            Withboth = 0x02,
            Notzero = 0x04,
            Check = 0x08,
            Rotation = 0x10,
            Continued = 0x20

        };

        //通过名字定义区区分
        public string name = "fiter";
        // 通过标签id区域
        public int tag = 0;
        //读取数据长度
        public int dataLenght = 1;
        //读取起始位置
        public int dataIndex = 0;
        //检测数组
        public byte[] checkDatas = new byte[1];
        //缓存数据
        public byte[] cacheDatas = new byte[1];

        //是否触发
        public bool ischeck = false;


        //源始数据
        public byte[] source;
        //接收格式
        public FormatType format = FormatType.Default;


        public DataFiter(EventModel template = null)
        {
            if (template != null)
                InitForTemplate(template);
        }


        /// <summary>
        /// 是否名字
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public bool isName(string n)
        {
            return name == n;
        }
        /// <summary>
        /// 位置的数值
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        public int getNubmer(int i = 0)
        {
            return (int)cacheDatas[i];
        }

        /// <summary>
        /// 16进制字符串转成 byte[] 确保字符串16进制
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>    
        public static byte[] S16BStringToBytes(string data)
        {
            byte[] bdata = new byte[data.Length / 2];
            for (int i = 0; i < data.Length / 2; i++)
                bdata[i] = Convert.ToByte(data.Substring(i * 2, 2), 16);


            return bdata;
        }

        /// <summary>
        /// byte[] to string 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string DataString(byte[] data)
        {
            string da = "";
            for (int i = 0; i < data.Length; i++)
                da += " " + data[i].ToString("X2");
            return da;

        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void intit()
        {
            cacheDatas = new byte[dataLenght];
        }


        /// <summary>
        /// 数据是否包括检测的数据，
        /// </summary>
        /// <returns></returns>
        public bool DataInclueCheck()
        {
            return AincludeB(cacheDatas, checkDatas);
        }

        /// <summary>
        /// 过虑数据
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        public bool filter(byte[] datas)
        {

            //  Debug.Log("fiter:" + DataString(datas));

            if (datas == null)
                return false;

            source = datas;


            //任意类型
            if ((format & FormatType.Default) == FormatType.Default)
                return true;

            //没有足够的长度
            if (dataIndex + dataLenght > datas.Length)
                return false;

            //取出需要的部分
            byte[] cpdata = new byte[dataLenght];
            Array.Copy(datas, dataIndex, cpdata, 0, dataLenght);

            // Debug.Log ("fiter 1:" + dataToString (cpdata) + ":" + dataToString (tempdatas));

            //内容相同部分
            if ((format & FormatType.Withboth) == FormatType.Withboth)
            {
                if (checkEquals(cpdata, checkDatas))
                {
                    cacheDatas = cpdata;
                    return true;
                }
                return false;
            }
            //非零值 
            if ((format & FormatType.Notzero) == FormatType.Notzero)
            {
                if (NoZero(cpdata))
                {
                    cacheDatas = cpdata;
                    return true;
                }
                return false;
            }
            //按钮开关
            if ((format & FormatType.Check) == FormatType.Check)
            {
                //  Debug.Log("check >> " + DataFiter.DataString(cpdata) + ":" + DataFiter.DataString(checkDatas) + ":" + ischeck);

                if (AincludeB(cpdata, checkDatas))
                {
                    //  Debug.Log("check  a in b  >> +" + ischeck);
                    //已按下
                    if (ischeck)
                        return false;

                    ischeck = true;
                    cacheDatas = cpdata;
                    return true;
                }
                //弹起
                if (ischeck)
                {
                    ischeck = false;
                    cacheDatas = new byte[1];
                    return true;
                }
                return false;
            }

            //变化值
            if ((format & FormatType.Rotation) == FormatType.Rotation)
            {
                if (!checkEquals(cpdata, cacheDatas))
                {
                    cacheDatas = cpdata;
                    return true;
                }
                return false;
            }

            //持续包函值 
            if ((format & FormatType.Continued) == FormatType.Continued)
            {
                cacheDatas = cpdata;
                return AincludeB(cpdata, checkDatas);

            }

            return false;
        }

        /// <summary>
        ///  非零值数据
        /// </summary>
        /// <param name="a"></param>
        /// <returns></returns>
        public static bool NoZero(byte[] a)
        {
            if (a == null) return false;

            for (int i = 0; i < a.Length; i++)
                if (a[i] > 0x00)
                    return true;

            return false;
        }


        /// <summary>
        ///  A是否包括B的内容
        /// </summary>
        /// <param name="a1"></param>
        /// <param name="b2"></param>
        /// <returns></returns>
        public static bool AincludeB(byte[] a1, byte[] b2)
        {
            if (a1 == null || b2 == null) return false;

            if (a1.Length != b2.Length) return false;

            for (int i = 0; i < a1.Length; i++)
                if ((a1[i] & b2[i]) != b2[i])
                    return false;

            return true;
        }
        /// <summary>
        ///  检测二段数据是否相等
        /// </summary>
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <returns></returns>
        public static bool checkEquals(byte[] b1, byte[] b2)
        {
            if (b1 == null || b2 == null) return false;

            if (b1.Length != b2.Length) return false;

            for (int i = 0; i < b1.Length; i++)
                if (b1[i] != b2[i])
                    return false;

            return true;
        }

        /// <summary>
        ///  复制对象数据
        /// </summary>
        /// <param name="df"></param>
        ///
        public void InitDataFiter(DataFiter df)
        {
            name = df.name;

            tag = df.tag;

            dataLenght = df.dataLenght;

            dataIndex = df.dataIndex;

            cacheDatas = df.cacheDatas;

            source = df.source;

            format = df.format;

            ischeck = df.ischeck;

            checkDatas = df.checkDatas;

        }

        /// <summary>
        /// 克隆对象
        /// </summary>
        /// <returns></returns>

        public DataFiter CloneObject()
        {
            DataFiter d = new DataFiter();
            d.name = name;

            d.tag = tag;

            d.dataLenght = dataLenght;

            d.dataIndex = dataIndex;

            d.cacheDatas = cacheDatas;

            d.source = source;

            d.format = format;

            d.ischeck = ischeck;

            d.checkDatas = checkDatas;

            return d;
        }



        /// <summary>
        /// 使用模析初始化数据
        /// </summary>
        /// <param name="temp"></param>
        public void InitForTemplate(EventModel temp)
        {
            name = temp.name;
            tag = temp.tag;
            format = (FormatType)temp.dataType;
            dataIndex = (int)temp.dataIndex;
            dataLenght = (int)temp.dataLength;
            checkDatas = temp.checkdata;


        }

    }
}